package sokoban;

import java.io.IOException;
import java.util.Vector;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.LayerManager;
import javax.microedition.lcdui.game.TiledLayer;

public class GameMap {

	private LayerManager layerManager;

	private TiledLayer playerLayer;

	private TiledLayer mapLayer;

	private TiledLayer crateLayer;

	private Vector initialCratePos = new Vector();

	private Vector goalPos = new Vector();

	private Point initialPlayerPos;

	private Point playerPos;

	private int numOfMoves;

	private String author;

	private String title;

	public GameMap() {
		try {
			playerLayer = new TiledLayer(Constants.BOARD_WIDTH,
					Constants.BOARD_HEIGHT, Image
							.createImage("/images/GameGraphics.png"),
					Constants.CELL_WIDTH, Constants.CELL_HEIGHT);
			mapLayer = new TiledLayer(Constants.BOARD_WIDTH,
					Constants.BOARD_HEIGHT, Image
							.createImage("/images/GameGraphics.png"),
					Constants.CELL_WIDTH, Constants.CELL_HEIGHT);
			crateLayer = new TiledLayer(Constants.BOARD_WIDTH,
					Constants.BOARD_HEIGHT, Image
							.createImage("/images/GameGraphics.png"),
					Constants.CELL_WIDTH, Constants.CELL_HEIGHT);

			layerManager = new LayerManager();
			layerManager.append(playerLayer);
			layerManager.append(crateLayer);
			layerManager.append(mapLayer);
		} catch (IOException e) {
		}
	}

	public void reset() {
		crateLayer.fillCells(0, 0, 32, 32, 0);
		playerLayer.fillCells(0, 0, 32, 32, 0);
		playerLayer.setCell(initialPlayerPos.getX(), initialPlayerPos.getY(),
				Constants.PLAYER);
		playerPos = new Point(initialPlayerPos.getX(), initialPlayerPos.getY());
		for (int i = 0; i < initialCratePos.size(); i++) {
			Point p = (Point) initialCratePos.elementAt(i);
			crateLayer.setCell(p.getX(), p.getY(), Constants.CRATE);
		}
		numOfMoves = 0;
	}

	public void setCell(Point p, int type) {
		if (type == Constants.PLAYER) {
			playerLayer.setCell(p.getX(), p.getY(), type);
			mapLayer.setCell(p.getX(), p.getY(), Constants.GROUND);
			playerPos = new Point(p.getX(), p.getY());
			initialPlayerPos = new Point(p.getX(), p.getY());
		} else if (type == Constants.CRATE) {
			crateLayer.setCell(p.getX(), p.getY(), type);
			mapLayer.setCell(p.getX(), p.getY(), Constants.GROUND);
			initialCratePos.addElement(p);
		} else {
			mapLayer.setCell(p.getX(), p.getY(), type);
			if (type == Constants.GOAL) {
				goalPos.addElement(p);
			}
		}
	}

	public boolean playerCanMove(Point p, int dir) {
		int nextCrate = getNext(p.getX(), p.getY(), dir, crateLayer);
		int nextMap = getNext(p.getX(), p.getY(), dir, mapLayer);
		if (nextCrate == Constants.CRATE) {
			if (dir == Constants.MOVE_LEFT) {
				if (crateCanMove(p.getX() - 1, p.getY(), dir)) {
					return true;
				}
			} else if (dir == Constants.MOVE_RIGHT) {
				if (crateCanMove(p.getX() + 1, p.getY(), dir)) {
					return true;
				}
			} else if (dir == Constants.MOVE_UP) {
				if (crateCanMove(p.getX(), p.getY() - 1, dir)) {
					return true;
				}
			} else if (dir == Constants.MOVE_DOWN) {
				if (crateCanMove(p.getX(), p.getY() + 1, dir)) {
					return true;
				}
			}
			return false;
		} else if (nextMap == Constants.GROUND || nextMap == Constants.GOAL) {
			return true;
		}
		return false;
	}

	public int getNext(int x, int y, int dir, TiledLayer layer) {
		switch (dir) {
		case Constants.MOVE_LEFT:
			return layer.getCell(x - 1, y);
		case Constants.MOVE_RIGHT:
			return layer.getCell(x + 1, y);
		case Constants.MOVE_UP:
			return layer.getCell(x, y - 1);
		case Constants.MOVE_DOWN:
			return layer.getCell(x, y + 1);
		}
		return -1;
	}

	public boolean crateCanMove(int x, int y, int dir) {
		int nextMap = getNext(x, y, dir, mapLayer);
		int nextCrate = getNext(x, y, dir, crateLayer);
		if ((nextMap == Constants.GROUND || nextMap == Constants.GOAL)
				&& nextCrate != Constants.CRATE) {
			crateLayer.setCell(x, y, 0);
			if (dir == Constants.MOVE_LEFT) {
				x--;
			}
			if (dir == Constants.MOVE_RIGHT) {
				x++;
			}
			if (dir == Constants.MOVE_UP) {
				y--;
			}
			if (dir == Constants.MOVE_DOWN) {
				y++;
			}
			crateLayer.setCell(x, y, Constants.CRATE);
			return true;
		}
		return false;
	}

	public void HandleAction(int action) {
		playerLayer.setCell(playerPos.getX(), playerPos.getY(), 0);
		
		switch (action) {

		case Constants.MOVE_LEFT:
			if (playerPos.getX() > 0
					&& playerCanMove(playerPos, Constants.MOVE_LEFT)) {
				playerPos.moveLeft();
				numOfMoves++;
			}
			break;
		case Constants.MOVE_RIGHT:
			if (playerPos.getX() + 1 < Constants.BOARD_WIDTH
					&& playerCanMove(playerPos, Constants.MOVE_RIGHT)) {
				playerPos.moveRight();
				numOfMoves++;
			}
			break;
		case Constants.MOVE_UP:
			if (playerPos.getY() > 0
					&& playerCanMove(playerPos, Constants.MOVE_UP)) {
				playerPos.moveUp();
				numOfMoves++;
			}
			break;
		case Constants.MOVE_DOWN:
			if (playerPos.getY() + 1 < Constants.BOARD_HEIGHT
					&& playerCanMove(playerPos, Constants.MOVE_DOWN)) {
				playerPos.moveDown();
				numOfMoves++;
			}
			break;
		}
		playerLayer.setCell(playerPos.getX(), playerPos.getY(),
				Constants.PLAYER);

	}

	public boolean isGameFinished() {
		for (int i = 0; i < goalPos.size(); i++) {
			Point p = (Point) goalPos.elementAt(i);
			if (crateLayer.getCell(p.getX(), p.getY()) != Constants.CRATE) {
				return false;
			}
		}
		return true;
	}

	public void draw(Graphics g, int width, int height) {
		Point viewPos = new Point(playerPos.getX() - width
				/ (2 * Constants.CELL_WIDTH), playerPos.getY() - height
				/ (2 * Constants.CELL_HEIGHT));
		layerManager.setViewWindow(viewPos.getX() * Constants.CELL_WIDTH,
				viewPos.getY() * Constants.CELL_HEIGHT, width, height-Constants.STATUS_BAR_HEIGHT);
		layerManager.paint(g, 0, Constants.STATUS_BAR_HEIGHT);
	}

	public String getAuthor() {
		return author;
	}

	public void setAuthor(String author) {
		this.author = author;
	}

	public String getTitle() {
		return title;
	}

	public void setTitle(String title) {
		this.title = title;
	}

	public TiledLayer getCrateLayer() {
		return crateLayer;
	}

	public TiledLayer getMapLayer() {
		return mapLayer;
	}

	public TiledLayer getPlayerLayer() {
		return playerLayer;
	}

	public int getNumOfMoves() {
		return numOfMoves;
	}
}
